﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;

namespace SimpleSocket
{

    public delegate void ClientConnectedEventHandler(object sender, ClientConnectedEventArgs args);

    public class SimpleSocketServer
    {
        public event ClientConnectedEventHandler ClientConnected;

        public bool IsListening { get; private set; }
        public int Port { get; private set; }

        private Socket ListenSocket { get; set; }

        public SimpleSocketServer(int port)
        {
            Port = port;
        }

        public void Listen()
        {
            if (IsListening == true)
                return; // the socket is already listening.

            IsListening = true;
            BindSocket();
            ListenSocket.Listen(5);
            ListenSocket.BeginAccept(AcceptCallback, ListenSocket);
        }

        public void Close()
        {
            if (IsListening == false)
                return; // The socket is already stopped.

            IsListening = false;
            ListenSocket.Close();
        }

        private void BindSocket()
        {
            ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, Port);
            ListenSocket.Bind(endPoint);
        }

        private void AcceptCallback(IAsyncResult ar)
        {
            if (IsListening == false)
                return; // this function was called because the server was shutdown.

            // Get the socket that handles the client request.
            Socket listener = (Socket)ar.AsyncState;
            Socket client = listener.EndAccept(ar);

            SimpleSocketClient connection = new SimpleSocketClient(client);

            if (ClientConnected != null)
            {
                ClientConnectedEventArgs args = new ClientConnectedEventArgs(this, connection);
                ClientConnected.BeginInvoke(this, args, null, null);
            }

            ListenSocket.BeginAccept(AcceptCallback, listener);
        }
    }
}
